import json, re, random

from django.contrib.auth import login, authenticate, logout

from celery_tasks.sms.tasks import ccp_send_sms_code
from django.views import View
from django import http
from apps.users.libs.captcha.captcha import captcha
from django_redis import get_redis_connection
from apps.users.models import User


# Create your views here.


# 图片验证码
class ImageCodeView(View):
    def get(self, request):
        """
        获取图片验证码,保存到redis中 GET api/v1.0/imagecode
        :param request: cur
        :return: image
        """
        # 接收参数
        cur = request.GET.get('cur')
        pre = request.GET.get('pre')
        # 实现核心逻辑:captcha
        text, image = captcha.generate_captcha()
        redis_conn = get_redis_connection('verify_code')
        redis_conn.setex('img_%s' % cur, 300, text)
        # 响应结果
        return http.HttpResponse(image, content_type='image/jpg')


# 短信验证码
class SMSCodeView(View):
    def post(self, request):
        """
        短信验证码  /api/v1.0/smscode/
        :param request:mobile,id,text
        :return:json
        """
        # 接收参数
        data = json.loads(request.body.decode())
        mobile = data.get('mobile')
        cur = data.get('id')
        text_code_client = data.get('text')
        # 给手机号做标记
        redis_conn = get_redis_connection('verify_code')
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        if send_flag:
            return http.JsonResponse({'errno': 4201, 'errmsg': '频繁发送短信'})

        # 校验参数
        if not all([mobile, cur, text_code_client]):
            return http.JsonResponse({'errno': 4003, 'errmsg': '缺少参数'})
        if not re.match(r'1[3-9]\d{9}', mobile):
            return http.JsonResponse({'errno': 4103, 'errmsg': '参数mobile错误'})

        # 实现核心逻辑:图形验证码的--提取,删除,验证,短信验证码--生成,保存,发送
        text_code_server = redis_conn.get('img_%s' % cur)
        # 判断过期
        if not text_code_server:
            return http.JsonResponse({'errno': 4001, 'errmsg': '图形验证码失效'})
        # 删除
        redis_conn.delete('img_%s' % cur)
        # 统一格式
        text_code_server = text_code_server.decode()
        if text_code_client.lower() != text_code_server.lower():
            return http.JsonResponse({'errno': 4004, 'errmsg': '图形验证码错误'})
        # 生成短信验证码,保存,发送
        random_num = random.randint(0, 999999)
        sms_code = '%06d' % random_num
        pl = redis_conn.pipeline()
        pl.setex('sms_code_%s' % mobile, 300, sms_code)
        pl.setex('send_flag_%s' % mobile, 60, 1)
        pl.execute()
        # 发送短信,调用异步任务
        ccp_send_sms_code(mobile, sms_code)
        print(sms_code)
        # 响应结果
        return http.JsonResponse({'errno': 0, 'errmsg': '短信验证码发送成功'})


# 注册
class RegisterView(View):
    def post(self, request):
        """
        注册  POST /api/v1.0/users
        :param request: mobile,phonecode,password
        :return:
        """
        # 接收参数
        json_data = json.loads(request.body.decode())
        mobile = json_data.get('mobile')
        sms_code_client = json_data.get('phonecode')
        password = json_data.get('password')

        # 校验参数
        if not all([mobile, sms_code_client, password]):
            return http.JsonResponse({"errno": 4103, "errmsg": "缺少参数"})
        if not re.match(r'1[3-9]\d{9}', mobile):
            return http.JsonResponse({"errno": 4103, "errmsg": "参数mobile错误"})
        # 校验手机号是否重复注册
        try:
            count = User.objects.filter(mobile=mobile).count()
        except User.DoesNotExist:
            return http.JsonResponse({"errno": 4001, "errmsg": "数据库查询错误"})
        if count != 0:
            return http.JsonResponse({"errno": 4001, "errmsg": "手机号重复注册"})

        # 未注册过,校验密码
        if not re.match(r'^[a-zA-Z0-9_-]{8,20}$', password):
            return http.JsonResponse({'code': 4004, 'errmsg': '密码不符合格式要求'})

        # 判断输入的短信验证码内容是否正确--提取,判断过期,对比
        redis_conn = get_redis_connection('verify_code')
        sms_code_server = redis_conn.get('sms_code_%s' % mobile)

        if not sms_code_server:
            return http.JsonResponse({'code': 4004, 'errmsg': '验证码过期'})

        sms_code_server = sms_code_server.decode()
        if sms_code_client != sms_code_server:
            return http.JsonResponse({'code': 4004, 'errmsg': '验证码错误'})

        # 实现核心逻辑
        # 保存注册数据到数据库.django自带的保存注册数据,create_user()
        user = User.objects.create_user(username=mobile, mobile=mobile, password=password)
        # 设置状态保持, session
        login(request, user=user)
        # 设置cookie
        response = http.JsonResponse({"errno": "0", "errmsg": "注册成功"})
        response.set_cookie('mobile', mobile, max_age=14 * 24 * 3600)

        # 响应结果
        return response


# 登录
class LoginView(View):

    def post(self, request):
        # 登录 /api/v1.0/session
        # 接收参数
        json_data = json.loads(request.body.decode())
        mobile = json_data.get('mobile')
        password = json_data.get('password')

        # 校验参数
        if not all([mobile, password]):
            return http.JsonResponse({"errno": 4103, "errmsg": "缺少参数"})
        if not re.match(r'1[3-9]\d{9}', mobile):
            return http.JsonResponse({"errno": 4103, "errmsg": "参数mobile错误"})
        if not re.match(r'^[a-zA-Z0-9_-]{8,20}$', password):
            return http.JsonResponse({'code': 4004, 'errmsg': '密码不符合格式要求'})

        # 实现核心逻辑:认证用户登录,登录状态保持
        User.USERNAME_FIELD = 'mobile'
        user = authenticate(username=mobile, password=password)
        if not user:
            return http.JsonResponse({'code': 4004, 'errmsg': '用户名或密码错误'})

        login(request, user)
        # 首页用户名展示
        response = http.JsonResponse({"errno": "0", "errmsg": "登录成功"})
        response.set_cookie('mobile', mobile, max_age=14 * 24 * 3600)
        # 响应结果
        return response

    # 判断是否登录
    def get(self, request):
        if not request.user.is_authenticated:
            return http.JsonResponse({"errno": "4101", "errmsg": "未登录"})

        data = {
            'name': request.user.username,
            'user_id': request.user.id,
        }

        return http.JsonResponse({"errno": "0", "errmsg": "已登录", "data": data})

    # 退出登录
    def delete(self, request):
        # 清理登录状态logout()
        logout(request)
        # 清理用户名cookie
        response = http.JsonResponse({"errno": "0", "errmsg": "已登出"})
        response.delete_cookie('mobile')

        return response
